<template>
  <span>
    {{ value }}
  </span>
</template>

<script setup lang="ts">
import { computed, ref, watch, PropType } from 'vue'
import { TransitionPresets, useTransition } from '@vueuse/core'
import { isNumber } from '@/utils'

interface Props {
  /** 初始值 */
  startValue?: number
  /** 结束值 */
  endValue?: number
  /** 动画时长 */
  duration?: number
  /** 自动动画 */
  autoplay?: boolean
  /** 进制 */
  decimals?: number
  /** 前缀 */
  prefix?: string
  /** 后缀 */
  suffix?: string
  /** 分割符号 */
  separator?: string
  /** 小数点 */
  decimal?: string
  /** 使用缓冲动画函数 */
  useEasing?: boolean
  /** 缓冲动画函数类型 */
  transition?: keyof typeof TransitionPresets
}
const props = withDefaults(defineProps<Props>(), {
  startValue: 0,
  endValue: 2021,
  duration: 1500,
  autoplay: true,
  decimals: 0,
  prefix: '',
  suffix: '',
  separator: ',',
  decimal: '.',
  useEasing: true,
  transition: 'linear',
})
const emit = defineEmits<{
  (e: 'on-started'): void
  (e: 'on-finished'): void
}>()

const source = ref(props.startValue)
const disabled = ref(false)
let outputValue = useTransition(source)
const value = computed(() => formatNumber(outputValue.value))

// props 中的 startValue 改变后自动重新计数
watch(
  [() => props.startValue, () => props.endValue],
  () => {
    source.value = props.startValue
    if (props.autoplay) {
      start()
    }
  },
  { immediate: true }
)

// todo: 解决 onStarted 和 onFinished 在执行结束会被多次调用问题
function start() {
  outputValue = useTransition(source, {
    disabled,
    duration: props.duration,
    onStarted: () => emit('on-started'),
    onFinished: () => emit('on-finished'),
    ...(props.useEasing ? { transition: TransitionPresets[props.transition] } : {}),
  })
  source.value = props.endValue
}

function formatNumber(num: number | string) {
  if (!num) return ''
  const { decimals, decimal, separator, prefix, suffix } = props
  const number = Number(num).toFixed(decimals)

  const x = number.split('.')
  // 整数部分
  let x1 = x[0]
  // 如果存在小数部分，x2 为分隔符+小数部分
  const x2 = x.length > 1 ? decimal + x[1] : ''
  const rgx = /(\d+)(\d{3})/
  // 如果整数部分需要设置分隔
  if (separator && !isNumber(separator)) {
    // 整数位数大于3
    while (rgx.test(x1)) {
      // $2为3个数字组成的字符
      x1 = x1.replace(rgx, `$1${separator}$2`)
    }
  }
  return prefix + x1 + x2 + suffix
}
</script>

<style scoped></style>
